#pragma once
//#include "stdafx.h"
#include "RationalNumber.h"
#include <sstream>
namespace org
{
	namespace spark
	{
		namespace math
		{

RationalNumber *const RationalNumber::ZERO = new RationalNumber(0);
RationalNumber *const RationalNumber::ONE = new RationalNumber(1);

			RationalNumber::RationalNumber(long long numerator, long long denominator)
			{
				if (denominator == 0)
					denominator = 1;

				this->numerator = numerator;
				this->denominator = denominator;
				normalize();
			}

			RationalNumber::RationalNumber(RationalNumber *r)
			{
				this->numerator = r->numerator;
				this->denominator = r->denominator;

				// We don't need to normalize here
			}

			RationalNumber::RationalNumber(long long n)
			{
				this->numerator = n;
				this->denominator = 1;
			}

			RationalNumber::RationalNumber(double n)
			{
				// TODO: implement
				
			}

			org::spark::math::RationalNumber *RationalNumber::add(RationalNumber *b)
			{
				// TODO: possible overflow problems
				numerator = numerator * b->denominator + b->numerator * denominator;
				denominator = b->denominator * denominator;
				normalize();

				return this;
			}

			org::spark::math::RationalNumber *RationalNumber::sub(RationalNumber *b)
			{
				// TODO: possible overflow issues
				numerator = numerator * b->denominator - b->numerator * denominator;
				denominator = b->denominator * denominator;
				normalize();

				return this;
			}

			org::spark::math::RationalNumber *RationalNumber::div(RationalNumber *b)
			{
				numerator *= b->denominator;
				denominator *= b->numerator;
				normalize();

				return this;
			}

			org::spark::math::RationalNumber *RationalNumber::mul(RationalNumber *b)
			{
				// TODO: possible overflow problems
				numerator *= b->numerator;
				denominator *= b->denominator;
				normalize();

				return this;
			}

			void RationalNumber::normalize()
			{
				if (denominator < 0)
				{
					denominator = -denominator;
					numerator = -numerator;
				}

				long long p = numerator;
				long long q = denominator;
				long long r;

				if (q == 1)
					return;

				if (p < 0)
					p = -p;

				// Euclid's algorithm for the GCD of (p, q)
				for (r = p % q; r != 0; p = q, q = r, r = p % q)
					;

				numerator /= q;
				denominator /= q;
			}

			double RationalNumber::doubleValue()
			{
				return static_cast<double>(numerator) / denominator;
			}

			float RationalNumber::floatValue()
			{
				return static_cast<float>(numerator) / denominator;
			}

			int RationalNumber::intValue()
			{
				return static_cast<int>(numerator / denominator);
			}

			long long RationalNumber::longValue()
			{
				return numerator / denominator;
			}

			int RationalNumber::compareTo(RationalNumber *o)
			{
				// TODO: overflow issues
				long long result = numerator * o->denominator - o->numerator * denominator;

				if (result < 0)
					return -1;

				if (result > 0)
					return 1;

				return 0;
			}

			std::string RationalNumber::ToString()
			{
				std::string number;
			    std::string number2;
				std::stringstream strstream;
				strstream << numerator;
				strstream >> number;
				strstream << denominator;
				strstream >> number2;
				if (denominator == 1)
// There is no native C++ equivalent to 'toString':
					return number;

// There is no native C++ equivalent to 'toString':
				return number + "/" + number2;
			}

			int RationalNumber::GetHashCode()
			{
				return static_cast<int>(numerator) ^ static_cast<int>(denominator);
			}

			org::spark::math::RationalNumber *RationalNumber::parse(const std::string &str)
			{
				//ORIGINAL LINE: String[] tmp = str.split("/");
				//TO DO  C++ format
				
				const std::string *tmp = &str;
				/*
				if (tmp == 0 || tmp->length == 0)
					return ZERO;

				if (tmp->length == 1)
					return new RationalNumber(StringConverterHelpery::fromString<long long>(tmp[0]));
					*/
				return new RationalNumber(StringConverterHelpery::fromString<long long>(tmp[0]), StringConverterHelper::fromString<long long>(tmp[1]));
			}
		}
	}
}